﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Salary.Sys.Core.Infrastructure
{
    public abstract class SingletonBase<T> where T : SingletonBase<T>
    {
        // ReSharper disable once InconsistentNaming
        private static T? _inst;
        // ReSharper disable once StaticMemberInGenericType
        private static readonly object InstanceLock = new object();

        protected abstract bool AutoInitialization { get; }

        public static T GetInstance()
        {
            if (_inst != null) return _inst;
            lock (InstanceLock)
            {
                Thread.MemoryBarrier();
                if (_inst != null) return _inst;

                var type = typeof(T);
                var flags = System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic;

                var constructor = type.GetConstructor(flags, null, Type.EmptyTypes, null);
                if (constructor == null)
                    throw new InvalidOperationException(
                        $"Type {typeof(T).FullName} doesn't got a supported constructor.");

                _inst = constructor.Invoke(null) as T;
                if (_inst == null)
                    throw new InvalidCastException();

                if (_inst.AutoInitialization)
                    _inst.Initialize();

                return _inst;
            }
        }

        public static T Instance => GetInstance();

        public virtual void Initialize()
        {
            if (_inst == null || _inst.AutoInitialization == false) return;
        }

        public void EnsureInitialized()
        {
            Console.WriteLine("[Singleton] {0} initialized.", typeof(T).FullName);
        }
    }
}
